import {
  Action,
  CaseReducerActions,
  createSlice,
  CreateSliceOptions,
  SliceCaseReducers,
  SliceSelectors,
  ThunkDispatch,
} from '@reduxjs/toolkit';
import { useSelector } from 'react-redux';
import { useGenerateDispatch } from '@/helpers/dispatch.ts';
import { useGenerateActions } from '@/helpers/actions.ts';

export type ReduxDispatch<S, A extends Action = Action> = ThunkDispatch<
  S,
  null,
  A
>;
export type StringOnly<T> = T extends string ? T : never;

type Selector<T, State> = (state: State) => T;

export const mySliceCreator = <
  State,
  CaseReducers extends SliceCaseReducers<State>,
  SliceName extends string,
  Selectors extends SliceSelectors<State>,
>(
  options: CreateSliceOptions<
    State,
    CaseReducers,
    SliceName,
    SliceName,
    Selectors
  >,
) => {
  const reducerUniqueName = options.name;

  /** @ts-expect-error К каждому редюсеру добавляем экшен, который сбрасывает состояние на изначальное */
  options.reducers._init = () => options.initialState;

  const slice = createSlice(options);

  const buildSelector = <T>(
    selector: Selector<T, State>,
  ): readonly [() => T, Selector<T, State>] => {
    const useBuildSelectorHook = () => {
      return useSelector(selector);
    };

    return [useBuildSelectorHook, selector];
  };

  // eslint-disable-next-line react-hooks/rules-of-hooks
  const generateDispatch = useGenerateDispatch<
    State,
    SliceName,
    StringOnly<keyof CaseReducers>
  >(reducerUniqueName);

  // eslint-disable-next-line react-hooks/rules-of-hooks
  const generateActions = useGenerateActions<
    State,
    CaseReducerActions<CaseReducers, SliceName>,
    SliceName
  >(slice.actions, reducerUniqueName);

  return {
    ...slice,
    buildSelector,
    ...generateDispatch,
    ...generateActions,
  };
};
